﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.DataObjects.Filters
{
    public class NetworkInclusionSetting
    {
        #region props
        private string _NetworkName;
        /// <summary></summary>
        public string NetworkName
        {
            get
            {
                return this._NetworkName;
            }
            set
            {
                this._NetworkName = value;
            }
        }

        private List<EntityType> _IncludeEntityTypes;
        /// <summary></summary>
        public List<EntityType> IncludeEntityTypes
        {
            get
            {
                return this._IncludeEntityTypes;
            }
            set
            {
                this._IncludeEntityTypes = value;
            }
        }

        private List<EntityQuery> _IncludeQueries;
        /// <summary></summary>
        public List<EntityQuery> IncludeQueries
        {
            get
            {
                return this._IncludeQueries;
            }
            set
            {
                this._IncludeQueries = value;
            }
        }

        private List<EdgeSelection> _IncludedEdges;
        /// <summary></summary>
        public List<EdgeSelection> IncludedEdges
        {
            get
            {
                return this._IncludedEdges;
            }
            set
            {
                this._IncludedEdges = value;
            }
        }
        #endregion

        public void Save()
        {
            string filePath = Path.Combine(DataFolder.NetworkDataFolder,
                                           this.NetworkName + DataFolder.NetworkInclusionSettingFileExtension);
            if (File.Exists(filePath))
                File.Delete(filePath);
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml("<NetworkIn></NetworkIn>");
            XmlNode root = xDoc.DocumentElement;
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "NetworkName", this.NetworkName);
            XmlNode exEntityNodes = XmlDataUtil.AddElement(ref xDoc, root, "InEntities");
            if (this.IncludeEntityTypes != null && this.IncludeEntityTypes.Count > 0)
            {
                foreach (EntityType entityType in this.IncludeEntityTypes)
                {
                    XmlNode exEntityNode = XmlDataUtil.AddElement(ref xDoc, exEntityNodes, "InEntity");
                    XmlDataUtil.UpdateAttribute(ref xDoc, exEntityNode, "EntityType", entityType.ToString());
                }
            }
            XmlNode exQueryNodes = XmlDataUtil.AddElement(ref xDoc, root, "InQueries");
            if (this.IncludeQueries != null && this.IncludeQueries.Count > 0)
            {
                foreach (EntityQuery query in this.IncludeQueries)
                {
                    XmlNode exQueryNode = XmlDataUtil.AddElement(ref xDoc, exQueryNodes, "InQuery");
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "EntityType", query.EntityType.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "FieldName", query.FieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "Op", query.Op.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, exQueryNode, "Against", query.Against);
                }
            }
            XmlNode exEdgeNodes = XmlDataUtil.AddElement(ref xDoc, root, "InEdges");
            if (this.IncludedEdges != null && this.IncludedEdges.Count > 0)
            {
                foreach (EdgeSelection edgeSelect in this.IncludedEdges)
                {
                    XmlNode exEdgeNode = XmlDataUtil.AddElement(ref xDoc, exEdgeNodes, "InEdge");
                    XmlDataUtil.UpdateAttribute(ref xDoc, exEdgeNode, "FromEntity", edgeSelect.FromEntity.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, exEdgeNode, "ToEntity", edgeSelect.ToEntity.ToString());
                }
            }

            xDoc.Save(filePath);
        }

        public static NetworkInclusionSetting Default
        {
            get
            {
                NetworkInclusionSetting ex = new NetworkInclusionSetting();
                ex.IncludedEdges = new List<EdgeSelection>();
                ex.IncludeEntityTypes = new List<EntityType>();
                ex.IncludeQueries = new List<EntityQuery>();
                ex.NetworkName = string.Empty;
                return ex;
            }
        }

        public static NetworkInclusionSetting Read(string networkName)
        {
            NetworkInclusionSetting ex = new NetworkInclusionSetting();
            string filePath = Path.Combine(DataFolder.NetworkDataFolder,
                                           networkName + DataFolder.NetworkInclusionSettingFileExtension);
            if (!File.Exists(filePath))
            {
                ex = NetworkInclusionSetting.Default;
                ex.NetworkName = networkName;
                return ex;
            }

            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(filePath);
            XmlNode root = xDoc.DocumentElement;
            ex.NetworkName = XmlDataUtil.GetAttributeValue(root, "NetworkName", "");
            XmlNodeList exEntityNodes = root.SelectNodes("InEntities/InEntity");
            ex.IncludeEntityTypes = new List<EntityType>();
            if (exEntityNodes != null && exEntityNodes.Count > 0)
            {
                foreach (XmlNode exEntityNode in exEntityNodes)
                {
                    EntityType entityType =
                        (EntityType)
                        Enum.Parse(typeof(EntityType),
                                   XmlDataUtil.GetAttributeValue(exEntityNode, "EntityType",
                                                                 EntityType.Grants.ToString()));
                    ex.IncludeEntityTypes.Add(entityType);
                }
            }
            ex.IncludeQueries = new List<EntityQuery>();
            XmlNodeList exQueryNodes = root.SelectNodes("InQueries/InQuery");
            if (exQueryNodes != null && exQueryNodes.Count > 0)
            {
                foreach (XmlNode exQNode in exQueryNodes)
                {
                    EntityQuery query = new EntityQuery();
                    query.EntityType =
                        (EntityType)
                        Enum.Parse(typeof(EntityType),
                                   XmlDataUtil.GetAttributeValue(exQNode, "EntityType", EntityType.Grants.ToString()));
                    query.FieldName = XmlDataUtil.GetAttributeValue(exQNode, "FieldName", "");
                    query.Op =
                        (SqlOp)
                        Enum.Parse(typeof(SqlOp), XmlDataUtil.GetAttributeValue(exQNode, "Op", SqlOp.Equals.ToString()));
                    query.Against = XmlDataUtil.GetAttributeValue(exQNode, "Against", "");
                    ex.IncludeQueries.Add(query);
                }
            }
            ex.IncludedEdges = new List<EdgeSelection>();
            XmlNodeList exEdgeNodes = root.SelectNodes("InEdges/InEdge");
            if (exEdgeNodes != null && exEdgeNodes.Count > 0)
            {
                foreach (XmlNode exEN in exEdgeNodes)
                {
                    EntityType fromEntity =
                        (EntityType)
                        Enum.Parse(typeof(EntityType),
                                   XmlDataUtil.GetAttributeValue(exEN, "FromEntity", EntityType.Grants.ToString()));
                    EntityType toEntity =
                        (EntityType)
                        Enum.Parse(typeof(EntityType),
                                   XmlDataUtil.GetAttributeValue(exEN, "ToEntity", EntityType.Grants.ToString()));
                    EdgeSelection edgeSelection = new EdgeSelection(fromEntity, toEntity);
                    ex.IncludedEdges.Add(edgeSelection);
                }
            }
            return ex;
        }

        public bool IsEnabled
        {
            get
            {
                if (this.IncludedEdges != null && this.IncludedEdges.Count > 0)
                    return true;
                if (this.IncludeEntityTypes != null && this.IncludeEntityTypes.Count > 0)
                    return true;
                if (this.IncludeQueries != null && this.IncludeQueries.Count > 0)
                    return true;
                return false;
            }
        }
    }
}
